/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  Rand.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2016/08/20
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "Rand.h"

#include <QDateTime>
#include <vector>

#include "gbkmap.h"

namespace qb {
namespace base {
class RandImpl {
  BaseString m_alphabet;
  BaseString m_numbers;
  BaseString m_cnstring;
  BaseString m_keystring;

 public:
  RandImpl() {
    qb::base::CGbkMap gbkmap;
    m_numbers = "0123456789";
    m_keystring = "~!@#$%^&*()_+{}:\"|<>?`-=[];'\\,./";
    m_alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    m_cnstring = gbkmap.GetAreaString(qb::base::kGbkHanziTypeGbk2).c_str();
  }
  static RandImpl& Get() {
    static RandImpl impl;
    return impl;
  }
  int RandInt(int mi, int mx) {
    // static boost::random::mt19937 rng;
    // static boost::uniform_int<> ui;
    // return mi + ui(rng)% (mx - mi);
    static int seed = 0x5412437;
    if (mx == mi) return mi;
    if (mi > mx) std::swap(mi, mx);

    uint32_t dt = QDateTime::currentMSecsSinceEpoch();
    srand(seed + dt);
    srand(seed);
    int last = rand();
    seed += last + dt;
    return mi + (last) % (mx - mi);
  }
  void RandString(BaseString& out, int minLength, int maxLength, DWORD flag) {
    if (flag & RSF_BASE64) {
      flag = RSF_Alphabet | RSF_Number;
    }
    int nselect = 0;
    DWORD flags[5] = {0};
    if (flag & RSF_Alphabet) {
      flags[nselect++] = RSF_Alphabet;
    }
    if (flag & RSF_Number) {
      flags[nselect++] = RSF_Number;
    }
    if (flag & RSF_CNWord) {
      flags[nselect++] = RSF_CNWord;
    }
    if (flag & RSF_Keyboard) {
      flags[nselect++] = RSF_Keyboard;
    }
    if (flag & RSF_CAPITAL) {
      flags[nselect++] = RSF_CAPITAL;
    }
    int len = RandInt(minLength, maxLength);
    out.expand(len);
    out.clear();
    for (int i = 0; i < len; i++) {
      int select = nselect > 1 ? RandInt(0, nselect) : 0;
      switch (flags[select]) {
        case RSF_Alphabet:
          out.push_back(m_alphabet[RandInt(0, m_alphabet.size())]);
          break;
        case RSF_CAPITAL:
          out.push_back(
              m_alphabet[RandInt(m_alphabet.size() / 2, m_alphabet.size())]);
          break;
        case RSF_Number:
          out.push_back(m_numbers[RandInt(0, m_numbers.size())]);
          break;
        case RSF_CNWord: {
          int pos = RandInt(0, m_cnstring.size() / 2);
          out.push_back(m_cnstring[pos * 2]);
          out.push_back(m_cnstring[pos * 2 + 1]);
          i++;
        } break;
        case RSF_Keyboard:
          out.push_back(m_keystring[RandInt(0, m_keystring.size())]);
          break;
      }
    }
  }
};
namespace {
static double resmaxd = 1.0 / RAND_MAX;
static float resmax = 1.0f / RAND_MAX;
}  // namespace
class NumGeneratorImpl {
  class Node {
    bool m_must;

   public:
    Node() : m_must(true) {}
    virtual ~Node() {}
    bool IsMust() const { return m_must; }
    void SetMust(bool must) { m_must = must; }
    virtual void Build(std::string& str) {}
  };
  class Meta : public Node {  // 本身最多选取mx,最少选取mi
    int m_min, m_max;
    std::string m_chars;

   public:
    Meta(const char* str, int mi, int mx) : m_min(mi), m_max(mx) {
      int len = strlen(str);
      for (int i = 0; i < len; i++) {
        if (i + 2 < len && str[i + 1] == '-')  // 处理连字符,如0-9,a-zA-Z
        {
          for (char c = str[i]; c <= str[i + 2]; c++) {
            m_chars.push_back(c);
          }
          i += 2;
        } else
          m_chars.push_back(str[i]);
      }
    }
    virtual ~Meta() {}
    virtual void Build(std::string& str) {
      int ncount = qb::base::Rand::RandInt(m_min, m_max);
      for (int i = 0; i < ncount; i++) {
        int isel = qb::base::Rand::RandInt(0, m_chars.size());
        str.push_back(m_chars[isel]);
      }
    }
  };
  class MetaLine : public Node {  // 每个节点都必选
    struct NodeInfo {
      Node* node;
      int mi, mx;
    };
    std::vector<Node*> m_steps;

   public:
    MetaLine() {}
    virtual ~MetaLine() {
      for (int i = 0; i < (int)m_steps.size(); i++) {
        delete m_steps[i];
      }
    }
    MetaLine(const std::initializer_list<Node*>& nodes) {
      m_steps.assign(nodes.begin(), nodes.end());
      for (auto it = m_steps.begin(); it != m_steps.end(); ++it)
        (*it)->SetMust(true);
    }
    void AddNode(Node* child, bool must) {
      child->SetMust(must);
      m_steps.push_back(child);
    }
    virtual void Build(std::string& str) {
      for (int i = 0; i < (int)m_steps.size(); i++) {
        Node* sub = m_steps[i];
        if (sub->IsMust() || qb::base::Rand::RandInt(0, 100) % 2 == 0)
          sub->Build(str);
      }
    }
  };
  class MetaSelect : public Node {  // 在多个MetaLine之间选取一个
    std::vector<MetaLine*> m_lines;

   public:
    MetaSelect(const std::initializer_list<MetaLine*>& lines) {
      m_lines.assign(lines.begin(), lines.end());
    }
    virtual ~MetaSelect() {
      for (int i = 0; i < (int)m_lines.size(); i++) {
        delete m_lines[i];
      }
    }
    virtual void Build(std::string& str) {
      int select = qb::base::Rand::RandInt(0, m_lines.size());
      if (select >= 0 && select < (int)m_lines.size())
        m_lines[select]->Build(str);
    }
  };
  MetaLine* m_root;
  int m_int_count;    // 最大整数长度
  int m_digit_count;  // 最大小数长度
  int m_exp_count;    // 最大指数长度
 public:
  NumGeneratorImpl()
      : m_int_count(12), m_digit_count(6), m_exp_count(2), m_root(nullptr) {}
  ~NumGeneratorImpl() {
    if (m_root) delete m_root;
  }
  void SetIntPartCount(unsigned int count) { m_int_count = count; }
  void SetDigitPartCount(unsigned int count) { m_digit_count = count; }
  void SetExpPartCount(unsigned int count) { m_exp_count = count; }
  std::string Build() {
    Init();
    std::string str;
    if (m_root == nullptr) return str;
    m_root->Build(str);
    return str;
  }

 protected:
  void Init() {
    if (m_root) return;
    // 正则表达式:"[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?"
    MetaLine* m1 = new MetaLine();
    m1->AddNode(new Meta("0-9", 1, m_int_count), true);
    m1->AddNode(
        new MetaLine({new Meta(".", 1, 1), new Meta("0-9", 0, m_digit_count)}),
        false);
    MetaLine* m2 =
        new MetaLine({new Meta(".", 1, 1), new Meta("0-9", 1, m_digit_count)});
    MetaLine* m3 = new MetaLine({new Meta("eE", 1, 1), new Meta("+-", 0, 1),
                                 new Meta("0-9", 1, m_exp_count)});
    MetaLine* root = new MetaLine();
    root->AddNode(new Meta("+-", 0, 1), true);
    root->AddNode(new MetaSelect({m1, m2}), true);
    root->AddNode(m3, false);
    m_root = root;
  }
};

int Rand::RandInt(int mi, int mx) { return RandImpl::Get().RandInt(mi, mx); }
float Rand::RandFloat(float mi, float mx) {
  if (mi >= mx) std::swap(mi, mx);
  int num = (int)(mx - mi);
  float f = RandInt(0, num + 1) + RandInt(0, RAND_MAX) * resmax;
  return f;
}
double Rand::RandDouble(double mi, double mx) {
  if (mi >= mx) std::swap(mi, mx);
  int num = (int)(mx - mi);
  double f = RandInt(0, num + 1) + RandInt(0, RAND_MAX) * resmaxd;
  return f;
}
float Rand::RandAround(float base, float percentage) {
  percentage =
      percentage > 1.0f ? 1.0f : (percentage < -1.0f ? -1.0f : percentage);
  return base * (1.0f + RandFloat(-percentage, percentage));
}

double Rand::RandAround(double base, double percentage) {
  percentage = percentage > 1.0 ? 1.0 : (percentage < -1.0 ? -1.0 : percentage);
  return base * (1.0 + RandDouble(-percentage, percentage));
}
BaseString Rand::RandNumString() {
  //
  // 第一步,手动将正则表达式翻译成序列生成器的调用
  // 第二部,编写算法自动将正则表达式翻译成序列生成器的调用
  static NumGeneratorImpl num_generator;
  return num_generator.Build().c_str();
}
BaseString Rand::RandString(int minLength, int maxLength, DWORD flag) {
  BaseString out;
  RandImpl::Get().RandString(out, minLength, maxLength, flag);
  return out;
}
void Rand::RandString(BaseString& out, int minLength, int maxLength,
                      DWORD flag) {
  RandImpl::Get().RandString(out, minLength, maxLength, flag);
}

RandNumGenerator::RandNumGenerator() : m_impl(new NumGeneratorImpl()) {}
RandNumGenerator::~RandNumGenerator() {
  if (m_impl) delete m_impl;
}
void RandNumGenerator::SetIntPartCount(unsigned int count) {
  m_impl->SetIntPartCount(count);
}
void RandNumGenerator::SetDigitPartCount(unsigned int count) {
  m_impl->SetDigitPartCount(count);
}
void RandNumGenerator::SetExpPartCount(unsigned int count) {
  m_impl->SetExpPartCount(count);
}
std::string RandNumGenerator::Generate() { return m_impl->Build(); }
}  // namespace base
}  // namespace qb
